package com.youlu.campus.service.visitor.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.req.UserCaReceivePointReq;
import com.youlu.campus.entity.VO.req.UserPointsQuerVO;
import com.youlu.campus.entity.VO.res.UserCaReceivePointRes;
import com.youlu.campus.entity.ca.UserCa;
import com.youlu.campus.entity.domain.UserPointsDomain;
import com.youlu.campus.entity.enums.CaMaterialType;
import com.youlu.campus.service.ca.UserCaReceiveRecordService;
import com.youlu.campus.service.ca.UserCaService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.platform.PointPlatformConfigService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.visitor.UserPointDailySignInService;
import com.youlu.campus.service.visitor.UserPointsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;


@Slf4j
@Service
public class UserPointsServiceImpl implements UserPointsService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserPointDailySignInService userPointDailySignInService;

    @Autowired
    private PointPlatformConfigService pointPlatformConfigService;

    @Autowired
    private UserCaReceiveRecordService userCaReceiveRecordService;

    @Lazy
    @Autowired
    private UserCaService userCaService;

    @Lazy
    @Autowired
    private UserInfoExtendService userInfoExtendService;


    @Override
    public UserPoints findByUserId(String userId, String appId) {
        if (StringUtils.isBlank(userId)) {
            log.error(":>>> 获取用户记分参数错误:userId为空");
            throw new BusinessException("获取用户记分参数错误");
        }
        Query query = new Query().addCriteria(Criteria.where("userId").is(userId));
        if (StringUtils.isNotBlank(appId)) {
            query.addCriteria(Criteria.where("appId").is(appId));
        }
        UserPoints userPoints = mongoTemplate.findOne(query, UserPoints.class);
        return userPoints;
    }

    @Override
    public Page<UserPointsDetail> list(UserPointsQuerVO req) {
        if (Objects.isNull(req) || Objects.isNull(req.getPage()) || Objects.isNull(req.getPageSize())) {
            log.error(":>>> 获取记分明细参数错误");
            throw new BusinessException("获取记分明细参数错误");
        }
        Query query = new Query();
        if (StringUtils.isNotBlank(req.getUserId())) {
            query.addCriteria(Criteria.where("userId").is(req.getUserId()));
        }
        if (StringUtils.isNotBlank(req.getPlatform())) {
            query.addCriteria(Criteria.where("platform").is(req.getPlatform()));
        }
        if (StringUtils.isNotBlank(req.getAppId())) {
            query.addCriteria(Criteria.where("appId").is(req.getAppId()));
        }
        Long count = mongoTemplate.count(query, UserPointsDetail.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort=Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<UserPointsDetail> infos = mongoTemplate.find(query.with(pageRequest), UserPointsDetail.class);
        return PageableExecutionUtils.getPage(infos, pageRequest, () -> count);
    }

    //@Async
    @Override
    public boolean addPoint(UserPointsDetail req) {
        log.info(":>>>  开始累加用户积分:{}", JSON.toJSON(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getAction()) || StringUtils.isBlank(req.getBizType()) ||
                StringUtils.isBlank(req.getBizDesc()) || StringUtils.isBlank(req.getComments())
                || Objects.isNull(req.getOptDate()) || StringUtils.isBlank(req.getUserId()) || Objects.isNull(req.getPoints())) {

            log.error(":.>> 累加积分参数错误");
            return false;
        }
        Date date = new Date();
        req.setCreatedTime(date);
        mongoTemplate.insert(req);
        UserPO user = new UserPO();
        user.setId(req.getUserId());
        user.setAppId(req.getAppId());
        user.setCurrentPlatform(req.getPlatform());
        UserPoints userPoints = this.findByUserInfo(user);
        if (Objects.isNull(userPoints)) {
            userPoints = new UserPoints();
            userPoints.setUserId(req.getUserId());
            userPoints.setCreatedTime(date);
            userPoints.setAppId(req.getAppId());
            userPoints.setPlatform(req.getPlatform());
            if ("add".equals(req.getAction())) {
                userPoints.setPoint(req.getPoints());
            }
            mongoTemplate.insert(userPoints);
            return true;
        }
        Update update = new Update();
        update.inc("point", req.getPoints());
        update.set("updatedTime", date);
        UpdateResult updateResult = mongoTemplate.updateFirst(new Query().addCriteria(Criteria.where("id").is(userPoints.getId())), update, UserPoints.class);
        return updateResult.getModifiedCount() > 0 ? true : false;
    }

    @Async
    @Override
    public void subPoint(UserPointsDetail req) {
        log.info(":>>>  开始扣减积分:{}", JSON.toJSON(req));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getAction()) || StringUtils.isBlank(req.getBizType()) ||
                StringUtils.isBlank(req.getBizDesc()) || StringUtils.isBlank(req.getComments())
                || Objects.isNull(req.getOptDate()) || StringUtils.isBlank(req.getUserId()) || Objects.isNull(req.getPoints())) {

            log.error(":.>> 扣减积分参数错误");
            return;
        }
        Date date = new Date();
        UserPoints userPoints = this.findByUserId(req.getUserId(), req.getAppId());
        if (Objects.isNull(userPoints)) {
            log.error(":>>> 用户积分记录不存在:{}", req.getUserId());
            throw new BusinessException("用户积分记录不存在");
        }
        if (userPoints.getPoint().compareTo(req.getPoints()) == -1) {
            log.error(":>>> 用户积分余额不足");
            throw new BusinessException("积分余额不足");
        }
        req.setCreatedTime(date);
        mongoTemplate.insert(req);
        Update update = new Update();
        update.inc("point", -req.getPoints());
        update.set("updatedTime", date);
        UpdateResult updateResult = mongoTemplate.updateFirst(new Query().addCriteria(Criteria.where("id").is(userPoints.getId())), update, UserPoints.class);
        log.info("【扣减积分】更新用户 - > {} 扣减积分返回结果 - > {}", req.getUserId(), updateResult.getModifiedCount());
    }

    @Override
    public UserPointsDomain getMyPoint(String userId, String appId) {
        UserPoints userPoints = this.findByUserId(userId, appId);
        UserPointsDomain userPointsDomain = new UserPointsDomain();
        userPointsDomain.setUserId(userId);
        if (Objects.nonNull(userPoints)) {
            BeanUtils.copyProperties(userPoints, userPointsDomain);
        }
        PointPlatformConfig config = pointPlatformConfigService.find(appId);
        if(Objects.isNull(config)){
            return null;
        }
        userPointsDomain.setPointRule(config.getPointDetail());
        userPointsDomain.setCsInfo(config.getCsInfo());
        boolean signed = userPointDailySignInService.signIned(userId, new Date());
        userPointsDomain.getBizDatas().put("sign-in", signed);
        userPointsDomain.setCsQQNumber(config.getCsQQNumber());
        userPointsDomain.setHasMp(config.getHasMp());
        return userPointsDomain;
    }

    @Override
    public UserCaReceivePointRes checkReceiveCaPoint(UserCaReceivePointReq userCaReceivePointReq) {
        UserPO currentUser = userCaReceivePointReq.getCurrentUser();
        log.info("【积分】校验用户->{}积分", currentUser.getId());
        Integer point = pointPlatformConfigService.getPoint(userCaReceivePointReq.getBizType());
        UserCaReceivePointRes userCaReceivePoint = new UserCaReceivePointRes();
        userCaReceivePoint.setActivityId(userCaReceivePointReq.getActivityId());
        userCaReceivePoint.setCaLevel(userCaReceivePointReq.getCaLevel());
        userCaReceivePoint.setCaType(userCaReceivePointReq.getCaType());
        userCaReceivePoint.setCurrentSubPoint(point);
        Boolean userExist = userInfoExtendService.existByUserId(currentUser.getId());
        if (userExist) {
            userCaReceivePoint.setRegister(Boolean.TRUE);
        }
        UserPoints userPoints = this.findByUserId(currentUser.getId(), userCaReceivePointReq.getAppId());
        if (Objects.isNull(userPoints)) {
            return userCaReceivePoint;
        }
        //用户账户积分如果满足x扣减积分条件
        if (userPoints.getPoint() >= point) {
            userCaReceivePoint.setCaReceive(Boolean.TRUE);
        }
        CaMaterialType caMaterialType = CaMaterialType.DIGIT;
        if ("recieve-paper-ca".equals(userCaReceivePointReq.getBizType())) {
            caMaterialType = CaMaterialType.PAPER;
        }
        UserCa userCa = userCaService.findByUserIdAndCaTypeAndCaLevel(currentUser.getId(), userCaReceivePointReq.getCaType(), userCaReceivePointReq.getCaLevel(), userCaReceivePointReq.getActivityId());
        if (Objects.isNull(userCa)) {
            log.error("【电子证书领取】->用户不满足领取电子证书要求，未有想过等级 caType -> {} | level ->{}| userId ->{}|activityId ->{}", userCaReceivePointReq.getCaType(), userCaReceivePointReq.getCaLevel(), currentUser.getId(), userCaReceivePointReq.getActivityId());
            userCaReceivePoint.setCaReceive(Boolean.FALSE);
        }
        //是否领取过
        Boolean exist = userCaReceiveRecordService.existCaByUserIdAndCaTypeAndActivityId(currentUser.getId(), userCaReceivePoint.getCaType(), userCaReceivePoint.getActivityId(), caMaterialType);
        if (exist) {
            userCaReceivePoint.setCaReceived(Boolean.TRUE);
        }
        userCaReceivePoint.setTotalPoint(userPoints.getPoint());
        return userCaReceivePoint;
    }

    @Override
    public boolean hasPoint(String userId, String appId, String bizType) {
        Integer requiredPoint = pointPlatformConfigService.getPoint(bizType);
        UserPoints userPoints = this.findByUserId(userId, appId);
        if (Objects.isNull(userPoints)) {
            log.error(":>>> 用户积分为空:{}", userId);
            return false;
        }
        if (userPoints.getPoint().compareTo(requiredPoint) != -1) {
            return true;
        }
        return false;
    }

    @Override
    public UserPoints findByUserInfo(UserPO currentUser) {
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(currentUser.getId()));
        query.addCriteria(Criteria.where("appId").is(currentUser.getAppId()));
        query.addCriteria(Criteria.where("platform").is(currentUser.getCurrentPlatform()));
        return this.mongoTemplate.findOne(query, UserPoints.class);
    }
}
